/**
 * 配置数据实体，即PO(Persistent Object)
 * */
package org.zmhhxl.api.auth.domain.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.hibernate.Hibernate;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.GrantedAuthority;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

//@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
//@JsonIdentityInfo(
//      generator = ObjectIdGenerators.PropertyGenerator.class,
//      property = "id")
//配置数据实体，即PO(Persistent Object)
@Entity
@Table(name="role", uniqueConstraints = {@UniqueConstraint(columnNames = {"role_name"})})
@Getter
@Setter
@ToString
@EntityListeners(AuditingEntityListener.class)
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class Role implements GrantedAuthority, Serializable {
   private static final long serialVersionUID = -6963523161322981431L;

   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   @Column(name = "id", nullable = false)
   Long id;

   @Column(name = "role_code")
   String roleCode;

   @Column(name = "role_name", nullable = false)
   String roleName;

   @Column(name = "description")
   String description;

   @Column(name = "enabled")
   boolean enabled;

   @Column(name = "role_content")
   String roleContent;

   @Column(name = "create_id")
   String createId;
   @Column(name = "update_id")
   String updateId;
   @Column(name = "create_time")
   LocalDateTime createTime;
   @Column(name = "update_time")
   LocalDateTime updateTime;

//   @ManyToMany(targetEntity = UserInfo.class,
//         fetch = FetchType.EAGER)  //.LAZY
//   @JoinTable(name = "user_mtm_role",
//         joinColumns = {@JoinColumn(name = "role_id")},
//         inverseJoinColumns = {@JoinColumn(name = "user_id")})
//@JsonBackReference  //排除,避免循环，子对象
//@JsonProperty("userInfos")
   @ManyToMany(targetEntity = UserInfo.class,
               cascade = CascadeType.ALL,
               fetch = FetchType.LAZY,
               mappedBy = "authorities"
              )
   @ToString.Exclude
   @Fetch(FetchMode.JOIN)
   @JsonIgnore  //排除,避免循环，
   private Set<UserInfo> userInfos = new HashSet<>();

//   @ManyToMany(targetEntity = Permission.class, fetch = FetchType.LAZY)
//   @JoinTable(name = "role_permission", joinColumns = {@JoinColumn(name = "role_id")}, inverseJoinColumns = {@JoinColumn(name = "permission_id")})
//   @ToString.Exclude
//   private Set<Permission> permissions = Collections.emptySet();

   /**
    * If the <code>GrantedAuthority</code> can be represented as a <code>String</code>
    * and that <code>String</code> is sufficient in precision to be relied upon for an
    * access control decision by an {@link AuthorizationManager AccessDecisionManager} (or delegate), this
    * method should return such a <code>String</code>.
    * <p>
    * If the <code>GrantedAuthority</code> cannot be expressed with sufficient precision
    * as a <code>String</code>, <code>null</code> should be returned. Returning
    * <code>null</code> will require an <code>AccessDecisionManager</code> (or delegate)
    * to specifically support the <code>GrantedAuthority</code> implementation, so
    * returning <code>null</code> should be avoided unless actually required.
    *
    * @return a representation of the granted authority (or <code>null</code> if the
    * granted authority cannot be expressed as a <code>String</code> with sufficient
    * precision).
    */
   @Override
   public String getAuthority() {
      return this.roleName;
   }

   //   @Override
//   public String getAuthority() {
//      return "ROLE_" + this.roleName;
//   }

   @Override
   public boolean equals(Object o) {
      if (this == o) return true;
      if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;
      Role role = (Role) o;
      return id != null && Objects.equals(id, role.id);
   }

   @Override
   public int hashCode() {
      return getClass().hashCode();
   }

}
